package com.mach4.gamesuite;

import com.skiller.api.listeners.SKListenerInterface;
import com.skiller.api.operations.SKApplication;
import com.skiller.api.operations.SKTurnBasedTools;
import com.skiller.api.operations.SKTurnBasedTools.eTBGameEvent;
import com.skiller.api.operations.SKTurnBasedTools.eTBGameState;
import com.skiller.api.responses.SKGameMoveResponse;
import com.skiller.api.responses.SKGameStartedResponse;
import com.skiller.api.responses.SKStatusResponse;

public class TicTacToeManager
{
    public enum ePlayer 
    { 
        NONE, 
        OPPONENT, 
        ME;  
    }

    private TicTacToeActivity mBoardUI;
    private String mGameId;
    private boolean mMyTurn;
    private boolean mIsGameOwner;
    private ePlayer[][] mGameMatrix = new ePlayer[3][3];
    
    private SKTurnBasedTools mTurnbasedTools;
    private SKListenerInterface<SKGameMoveResponse> mMoveListener;
    private boolean mIsBackPressed;
    
    private static TicTacToeManager mInstance = new TicTacToeManager();
    
    private TicTacToeManager()
    {
        mTurnbasedTools = SKApplication.getInstance().getGameManager().getTurnBasedTools();
        
        mMoveListener = new SKListenerInterface<SKGameMoveResponse>() 
        {
            @Override
            public void onResponse(SKGameMoveResponse response)
            {               
                eTBGameState gameState = response.getGameState();
                String gameId = response.getGameId();
                String payload = response.getPayload();
                
                handleOpponentMove(gameState, gameId, payload);
            }

            @Override
            public void onError(SKStatusResponse response) {
                if (mIsBackPressed == false)
                    mBoardUI.showFinalDialog("Oops", response.getStatusMessage());
                
            }
        };
    }
    
    public static TicTacToeManager getInstance()
    {
        return mInstance;
    }
    
    public void createGame()
    {
        mTurnbasedTools.createGame(0, "TicTacToe", "TicTacToe", new SKListenerInterface<SKGameStartedResponse>() 
        {
            @Override
            public void onResponse(SKGameStartedResponse response)
            {
                handleStartResponse(response);
            }

            @Override
            public void onError(SKStatusResponse response) {
                mBoardUI.showFinalDialog("Oops", "Could not open the game. Please try again.");
            }
        }); 
    }
    
    public void joinGame(String gameId)
    {
        mTurnbasedTools.joinGame(gameId, new SKListenerInterface<SKGameStartedResponse>() 
        {
            @Override
            public void onResponse(SKGameStartedResponse response)
            {
                handleStartResponse(response);
            }

            @Override
            public void onError(SKStatusResponse response) {
                mBoardUI.showFinalDialog("Oops", "Could not join the game. Please try again.");
            }
        }); 
    }
    
    private void handleStartResponse(SKGameStartedResponse response)
    {
        mBoardUI.initBoard();
        mGameId = response.getGameId();
        mIsBackPressed = false;
        
        //clear the board
        for (int row = 0; row<3 ; row++)
            for (int col = 0; col<3 ; col++)
                mGameMatrix[row][col] = ePlayer.NONE;
        
        String ownerName = response.getOwner().getUserName();
        String currentUserName = SKApplication.getInstance().getUserManager().getCurrentUsername();
        
        //Choose who wants to make the first move:
        //The player that will not make the first move should send ready to play event and wait for opponents move
        if (ownerName.equals(currentUserName))
        {//In our case the owner of the game will wait for guests move, so we send ready to play event and wait for the move on the listener
            String payload = ""; //nothing to send
            String chatline = ""; //nothing to chat about
            mTurnbasedTools.makeMove(response.getGameId(), eTBGameEvent.GAME_EVENT_READY_TO_PLAY, payload, chatline, mMoveListener);
                    
            mIsGameOwner = true;
            mMyTurn = false;
        }
        else
        {//If you are the guest of the game, start playing
            mIsGameOwner = false;
            mMyTurn = true;
        }
    }
    
    private void quitGame() 
    {
        String payload = ""; //no payload to send when exiting the game
        String chatline = ""; //nothing to chat about;
        mTurnbasedTools.makeMove(mGameId, eTBGameEvent.GAME_EVENT_QUIT_GAME, payload, chatline, null);
        mBoardUI.showFinalDialog("Game over", "");
    }
    
    private void terminatePendingGame() 
    {
        mTurnbasedTools.terminatePendingGame(new SKListenerInterface<SKStatusResponse>()
        {
            @Override
            public void onResponse(SKStatusResponse response)
            {
                //Game was terminated successfully, show some message if you want to
            }

            @Override
            public void onError(SKStatusResponse response) {
                mBoardUI.showFinalDialog("Oops", "Could not terminate the game.");
            }
        });
    }
    
    public void onBackKeyPress()
    {
        mIsBackPressed = true;
        
        if (mGameId != null)
        {//If the game is in process, quit the game
            quitGame();
        }
        else
        {//If the game was not started yet, terminate it.
            terminatePendingGame();
        }
        
        mGameId = null;
    }
    
    
    private void handleOpponentMove(eTBGameState gameState, String gameId, String payload)
    {
        switch (gameState)
        {
            case GAME_STATE_ARE_YOU_HERE:
                String myPayload = ""; //no payload, just tell the server you are still in game
                String chatline = ""; //nothing to chat about
                mTurnbasedTools.makeMove(gameId, eTBGameEvent.GAME_EVENT_STILL_HERE, myPayload, chatline, mMoveListener);
                break;

            case GAME_STATE_LOST:
                mBoardUI.showFinalDialog("Game Over", "You Lost!");
                break;

            case GAME_STATE_TIED:
                mBoardUI.showFinalDialog("Game Over", "It's a Tie!");
                break;

            case GAME_STATE_WON:
                mBoardUI.showFinalDialog("Game Over", "You Won!");
                break;

            case GAME_STATE_IN_PROGRESS:
                int posRow = Integer.parseInt(payload.substring(0, 1));
                int posCol = Integer.parseInt(payload.substring(1, 2));
                handleMove(gameId, posRow, posCol, ePlayer.OPPONENT);
                break;
                
            case GAME_ERROR:
            default:
                mBoardUI.showFinalDialog("Game Over", "An error occurred.");
                break;
        }
    }
    
    public void handleMyMove(int posRow, int posCol)
    {
        handleMove(mGameId, posRow, posCol, ePlayer.ME);
    }
    
    private synchronized void handleMove(String gameId, final int posRow, final int posCol, final ePlayer player)
    {
        if (!mMyTurn && player == ePlayer.ME)
            return;
        
        eTBGameState gameState = updateMove(posRow, posCol, player);
        if (gameState == eTBGameState.GAME_ERROR)
        {//If illegal move was made by the player himself do nothing
            if (player == ePlayer.OPPONENT)
            {//If illegal move was made by the opponent finish the game
                mBoardUI.showFinalDialog("Oops","Opponent made illegal move.");
            }
            
            return;
        }
            
        boolean isMoveOwner = (mIsGameOwner && player == ePlayer.ME) || (!mIsGameOwner && player == ePlayer.OPPONENT);
        mBoardUI.drawMove(posRow, posCol, isMoveOwner);

        if (player == ePlayer.OPPONENT)
            mMyTurn = true; 
        else if (player == ePlayer.ME)
            mMyTurn = false;
           
        String payload = "";
        if (player == ePlayer.ME)
            payload = posRow + "" + posCol; 

        String chatLine = "";
        
        switch (gameState)
        {
            case GAME_STATE_WON:
                mTurnbasedTools.makeMove(gameId, eTBGameEvent.GAME_EVENT_CLAIM_WIN, payload, chatLine, mMoveListener);
                break;

            case GAME_STATE_LOST:
                mTurnbasedTools.makeMove(gameId, eTBGameEvent.GAME_EVENT_CLAIM_LOSE, payload, chatLine, mMoveListener);
                break;

            case GAME_STATE_TIED:
                mTurnbasedTools.makeMove(gameId, eTBGameEvent.GAME_EVENT_CLAIM_TIE, payload, chatLine, mMoveListener);
                break;

            case GAME_STATE_IN_PROGRESS:
                if (player == ePlayer.ME)
                {//this was my move, update opponent about it
                    mTurnbasedTools.makeMove(gameId, eTBGameEvent.GAME_EVENT_MAKING_MOVE, payload, chatLine, mMoveListener);
                }
                
                //in case this is an opponent move, we need to wait for the current player to make canvas move
                break;
        }
    }
    
    private eTBGameState updateMove(int aRowPos, int aColPos, ePlayer aPlayer)
    {
        if (mGameMatrix[aRowPos][aColPos] != ePlayer.NONE)
            return eTBGameState.GAME_ERROR;

        mGameMatrix[aRowPos][aColPos] = aPlayer;
        
        ePlayer winner = ePlayer.NONE;
        boolean isFullMatrix = true;

        //check rows
        for(int x = 0; x < 3; ++x)
        {
            winner = mGameMatrix[x][0];
            for(int y = 0; y < 3; ++y)
            {
                if (winner != ePlayer.NONE && winner != mGameMatrix[x][y])
                    winner = ePlayer.NONE;
                    
                if (mGameMatrix[x][y] == ePlayer.NONE)
                    isFullMatrix = false;
            }

            if (winner != ePlayer.NONE)
                return (winner == ePlayer.ME)? eTBGameState.GAME_STATE_WON : eTBGameState.GAME_STATE_LOST;
        }

        //check columns
        for(int y = 0; y < 3; ++y)
        {
            winner = mGameMatrix[0][y];
            for(int x = 0; x < 3; ++x)
            {
                if (winner != ePlayer.NONE && winner != mGameMatrix[x][y])
                    winner = ePlayer.NONE;
                    
                if (mGameMatrix[x][y] == ePlayer.NONE)
                    isFullMatrix = false;
            }

            if (winner != ePlayer.NONE)
                return (winner == ePlayer.ME)? eTBGameState.GAME_STATE_WON : eTBGameState.GAME_STATE_LOST;
        }

        //check first diagonal
        winner = mGameMatrix[0][0];
        for(int i = 1; i < 3; ++i)
        {
            if (winner != mGameMatrix[i][i])
            {
                winner = ePlayer.NONE;
                break;
            }
        }

        if (winner != ePlayer.NONE)
            return (winner == ePlayer.ME)? eTBGameState.GAME_STATE_WON : eTBGameState.GAME_STATE_LOST;

        //check second diagonal
        winner = mGameMatrix[0][2];
        for(int i = 1; i < 3; ++i)
        {
            if (winner != mGameMatrix[i][2-i])
            {
                winner = ePlayer.NONE;
                break;
            }
        }

        if (winner != ePlayer.NONE)
            return (winner == ePlayer.ME)? eTBGameState.GAME_STATE_WON : eTBGameState.GAME_STATE_LOST;
   
        if (isFullMatrix)
            return eTBGameState.GAME_STATE_TIED;
        
        return eTBGameState.GAME_STATE_IN_PROGRESS;
    }
    
    public void setBoardUI(TicTacToeActivity context)
    {
        this.mBoardUI = context;
    }
}
